/*************************************************
* Title：TinyToolKit
* Author：Opportunity 
* Describe：实现滑动切换图片的功能
* CreateTime：2020-05-19 15:04:17
* Version：1.0
* Modify Recorder：
*************************************************/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace TinyToolKit
{
    [RequireComponent(typeof(ScrollRect))]
    public class Viewpager : MonoBehaviour, IBeginDragHandler, IEndDragHandler
    {
        public float sensitivity = 2;
        public float duration = 0.5f;
        public AnimationCurve smoothCurve = AnimationCurve.Linear(0,0,1,1);
        public UnityEvent onPageChanged;
        
        public int PageCount { get; private set; }
        public int CurPageIndex { get;private set; }
        
        private ScrollRect _rect;
        private float _targetPos;
        private float _curPos;
        private bool _isDrag;
        [SerializeField] private List<float> _posList = new List<float>();
        private float _startDragHorizontal;
        private bool _canSwitch = true;
        
        private void Awake()
        {
            _rect = gameObject.GetComponent<ScrollRect>();
            ResetPosList();
        }
        
        public void PageToNext()
        {
            PageTo(CurPageIndex + 1);
        }
        
        public void PageToPre() 
        {
            PageTo(CurPageIndex - 1);
        }

        #region Internal Func
        
        private void PageTo(int pageIndex)
        {
            if (pageIndex >= 0 && pageIndex < PageCount)
            {
                SetPageIndex(pageIndex);
            }
        }
        
        private void SetPageIndex(int pageIndex) 
        {
            if (_canSwitch)
            {
                _canSwitch = false;
                _curPos = _rect.horizontalNormalizedPosition;
                _targetPos = _posList[pageIndex];
                CurPageIndex = pageIndex;
                StopCoroutine("MoveSmooth");
                StartCoroutine("MoveSmooth");
            }
        }
        
        private void ResetPosList()
        {
            CurPageIndex = 0;
            _curPos = 0;
            _targetPos = 0;
            _rect.horizontalNormalizedPosition = _targetPos;
            float rectWidth = GetComponent<RectTransform>().rect.width;
            PageCount = _rect.content.childCount;
            float horizontalLength = (PageCount - 1) * rectWidth;

            //记录每一个页面在ScrollRect中的horizontalNormalizedPosition的值
            _posList.Clear();
            _posList.Add(0);
            for (int i = 1; i < PageCount - 1; i++)
            {
                _posList.Add(rectWidth * i / horizontalLength);
            }
            _posList.Add(1);
        }

        public void OnBeginDrag(PointerEventData eventData)
        {
            _isDrag = true;
            _startDragHorizontal = _rect.horizontalNormalizedPosition;
        }

        public void OnEndDrag(PointerEventData eventData)
        {
            _isDrag = false;
            float posX = _rect.horizontalNormalizedPosition;
            float offset = (posX - _startDragHorizontal) * sensitivity;
            posX += offset;
            posX = Mathf.Clamp01(posX);

            //查找距离当前位置最近的页面
            int index = 0;
            float dis = Mathf.Infinity;
            for (int i = 0; i < _posList.Count; i++)
            {
                float temp = Mathf.Abs(_posList[i] - posX);
                if (temp < dis)
                {
                    index = i;
                    dis = temp;
                }
            }
            SetPageIndex(index);
        }

        IEnumerator MoveSmooth()
        {
            for (float i = 0; i <= duration; i += Time.deltaTime)
            {
                float t = Mathf.Clamp01(smoothCurve.Evaluate(i / duration));
                _rect.horizontalNormalizedPosition = Mathf.Lerp( _curPos, _targetPos,  t);
                yield return null;
            }
            
            _rect.horizontalNormalizedPosition = _targetPos;
            _canSwitch = true;
            
            onPageChanged?.Invoke();
        }

        #endregion
    }
}